package com.joker.demo.core.executor.impl;

import com.joker.demo.core.annotation.JobHandle;
import com.joker.demo.core.config.JobExecutorProperties;
import com.joker.demo.core.domain.bo.JobRegistryDetailBO;
import com.joker.demo.core.domain.dto.JobExecutorParamsDTO;
import com.joker.demo.core.domain.dto.JobExecutorResultDTO;
import com.joker.demo.core.domain.dto.TaskExecuteRequestDTO;
import com.joker.demo.core.executor.JobExecutor;
import com.joker.demo.core.executor.JobExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 任务执行器 - 普通Java项目版本
 * <p>
 * 这个类专门为不依赖Spring Boot的普通Java项目设计，提供以下功能：
 * 1. 自动扫描指定包下的任务处理器
 * 2. 支持类级别和方法级别的@JobHandle注解
 * 3. 支持从文件系统和JAR包中扫描类
 * 4. 提供手动注册任务处理器的方法
 * <p>
 * 使用方式：
 * 1. 在类或方法上添加@JobHandle注解
 * 2. 创建JobExecutorSimpleExecutor实例
 * 3. 调用start()方法启动执行器
 *
 * @author : feixiang.li
 * @since : 2025-07-24 16:57
 */
public class JobExecutorSimpleExecutor extends JobExecutor {

    /**
     * 日志记录器
     */
    private static final Logger log = LoggerFactory.getLogger(JobExecutorSimpleExecutor.class);

    /**
     * 存储任务名称到处理方法的映射
     */
    private final Map<String, Method> jobHandlerMap = new ConcurrentHashMap<>();

    /**
     * 存储任务名称到处理器实例的映射
     */
    private final Map<String, Object> jobHandlerInstanceMap = new ConcurrentHashMap<>();

    /**
     * 任务执行器配置
     */
    private final JobExecutorProperties properties;

    /**
     * 要扫描的包名
     */
    private String scanPackage;

    /**
     * 构造函数
     *
     * @param config      执行器配置
     * @param scanPackage 要扫描的包名，如果指定了包名会自动扫描该包下的任务处理器
     */
    public JobExecutorSimpleExecutor(JobExecutorProperties config, String scanPackage) {
        super(config);
        this.properties = config;
        this.scanPackage = scanPackage;

        // 如果指定了扫描包，则自动扫描并注册任务处理器
        if (scanPackage != null && !scanPackage.trim().isEmpty()) {
            scanAndRegisterHandlersFromPackage();
        }
    }

    /**
     * 基于scanPackage自动扫描并注册任务处理器
     * <p>
     * 扫描过程：
     * 1. 在指定包下查找所有类
     * 2. 检查类和方法上的@JobHandle注解
     * 3. 将找到的任务处理器注册到映射表中
     */
    public void scanAndRegisterHandlersFromPackage() {
        if (scanPackage == null || scanPackage.trim().isEmpty()) {
            log.warn("未指定扫描包，跳过自动扫描");
            return;
        }

        log.info("开始扫描包: {}", scanPackage);

        try {
            // 在指定包下查找所有类
            List<Class<?>> classes = findClassesInPackage(scanPackage);
            log.info("在包 {} 中找到 {} 个类", scanPackage, classes.size());

            // 遍历每个类，检查是否有任务处理器
            for (Class<?> clazz : classes) {
                try {
                    // 检查类上是否有@JobHandle注解
                    JobHandle classAnnotation = clazz.getAnnotation(JobHandle.class);
                    if (classAnnotation != null) {
                        // 类级别的任务处理器
                        if (JobExecutorService.class.isAssignableFrom(clazz)) {
                            // 创建类实例并注册
                            Object instance = clazz.getDeclaredConstructor().newInstance();
                            registerJobHandler(classAnnotation.value(), instance);
                        } else {
                            log.warn("类 {} 有@JobHandle注解但未实现JobExecutorService接口", clazz.getName());
                        }
                    }

                    // 扫描方法上的@JobHandle注解
                    Object instance = null;
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        JobHandle methodAnnotation = method.getAnnotation(JobHandle.class);
                        if (methodAnnotation != null) {
                            // 延迟创建实例，只在需要时创建
                            if (instance == null) {
                                instance = clazz.getDeclaredConstructor().newInstance();
                            }
                            registerJobHandlerMethod(methodAnnotation.value(), instance, method);
                        }
                    }
                } catch (Exception e) {
                    log.error("处理类 {} 时发生错误", clazz.getName(), e);
                }
            }

            log.info("自动扫描完成，共注册 {} 个处理器", jobHandlerMap.size());
        } catch (Exception e) {
            log.error("扫描包 {} 时发生错误", scanPackage, e);
        }
    }

    /**
     * 在指定包中查找所有类
     * <p>
     * 支持从文件系统和JAR包中查找类
     *
     * @param packageName 包名
     * @return 找到的类列表
     */
    private List<Class<?>> findClassesInPackage(String packageName) {
        List<Class<?>> classes = new ArrayList<>();

        try {
            // 将包名转换为路径格式
            String packagePath = packageName.replace('.', '/');
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Enumeration<URL> resources = classLoader.getResources(packagePath);

            // 遍历所有资源
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                String protocol = resource.getProtocol();

                if ("file".equals(protocol)) {
                    // 处理文件系统中的类（开发环境）
                    findClassesInDirectory(new File(resource.getFile()), packageName, classes);
                } else if ("jar".equals(protocol)) {
                    // 处理JAR文件中的类（生产环境）
                    findClassesInJar(resource, packageName, classes);
                }
            }
        } catch (IOException e) {
            log.error("扫描包 {} 时发生IO错误", packageName, e);
        }

        return classes;
    }

    /**
     * 在目录中查找类（文件系统）
     *
     * @param directory   目录
     * @param packageName 包名
     * @param classes     用于存储找到的类的列表
     */
    private void findClassesInDirectory(File directory, String packageName, List<Class<?>> classes) {
        if (!directory.exists()) {
            return;
        }

        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                String fileName = file.getName();
                if (file.isDirectory()) {
                    // 递归扫描子目录
                    findClassesInDirectory(file, packageName + "." + fileName, classes);
                } else if (fileName.endsWith(".class")) {
                    // 加载类文件
                    String className = packageName + "." + fileName.substring(0, fileName.length() - 6);
                    try {
                        Class<?> clazz = Class.forName(className);
                        classes.add(clazz);
                    } catch (ClassNotFoundException e) {
                        log.debug("无法加载类: {}", className);
                    }
                }
            }
        }
    }

    /**
     * 在JAR文件中查找类
     *
     * @param jarUrl      JAR文件的URL
     * @param packageName 包名
     * @param classes     用于存储找到的类的列表
     */
    private void findClassesInJar(URL jarUrl, String packageName, List<Class<?>> classes) {
        // 解析JAR文件路径
        String jarPath = jarUrl.getPath();
        if (jarPath.startsWith("file:")) {
            jarPath = jarPath.substring(5);
        }
        if (jarPath.contains("!")) {
            jarPath = jarPath.substring(0, jarPath.indexOf("!"));
        }

        try (JarFile jarFile = new JarFile(jarPath)) {
            String packagePath = packageName.replace('.', '/');
            Enumeration<JarEntry> entries = jarFile.entries();

            // 遍历JAR文件中的所有条目
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();

                // 检查是否是目标包下的类文件
                if (entryName.startsWith(packagePath) && entryName.endsWith(".class")) {
                    String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');
                    try {
                        Class<?> clazz = Class.forName(className);
                        classes.add(clazz);
                    } catch (ClassNotFoundException e) {
                        log.debug("无法加载类: {}", className);
                    }
                }
            }
        } catch (IOException e) {
            log.error("读取JAR文件时发生错误: {}", jarPath, e);
        }
    }

    /**
     * 注册任务处理器（类级别）
     *
     * @param jobName 任务名称
     * @param handler 任务处理器实例
     */
    public void registerJobHandler(String jobName, Object handler) {
        if (handler instanceof JobExecutorService) {
            // 类级别的任务处理器
            jobHandlerMap.put(jobName, null);
            jobHandlerInstanceMap.put(jobName, handler);
            log.info("注册任务处理器类: {} -> {}", jobName, handler.getClass().getName());
        } else {
            log.error("任务处理器必须实现JobExecutorService接口: {}", jobName);
        }
    }

    /**
     * 注册任务处理器方法
     *
     * @param jobName  任务名称
     * @param instance 处理器实例
     * @param method   处理方法
     */
    public void registerJobHandlerMethod(String jobName, Object instance, Method method) {
        jobHandlerMap.put(jobName, method);
        jobHandlerInstanceMap.put(jobName, instance);
        log.info("注册任务处理器方法: {} -> {}.{}", jobName, instance.getClass().getName(), method.getName());
    }

    /**
     * 手动扫描并注册任务处理器
     * <p>
     * 用于手动注册任务处理器，不依赖包扫描
     *
     * @param handlers 要注册的处理器实例数组
     */
    public void scanAndRegisterHandlers(Object... handlers) {
        for (Object handler : handlers) {
            Class<?> handlerClass = handler.getClass();

            // 扫描类上的@JobHandle注解
            JobHandle classAnnotation = handlerClass.getAnnotation(JobHandle.class);
            if (classAnnotation != null) {
                if (handler instanceof JobExecutorService) {
                    registerJobHandler(classAnnotation.value(), handler);
                }
            }

            // 扫描方法上的@JobHandle注解
            Method[] methods = handlerClass.getMethods();
            for (Method method : methods) {
                JobHandle methodAnnotation = method.getAnnotation(JobHandle.class);
                if (methodAnnotation != null) {
                    registerJobHandlerMethod(methodAnnotation.value(), handler, method);
                }
            }
        }

        log.info("手动扫描完成，共注册 {} 个处理器", jobHandlerMap.size());
    }


    /**
     * 获取要注册到调度中心的任务处理器列表
     * <p>
     * 遍历所有已注册的任务处理器，构建注册信息
     *
     * @return 任务注册信息列表
     */
    @Override
    public List<JobRegistryDetailBO> getRegisterJobHandlers() {
        log.info("开始构建任务处理器注册信息");

        List<JobRegistryDetailBO> jobRegistryList = new ArrayList<>();

        // 遍历所有已注册的任务处理器
        for (String jobName : jobHandlerMap.keySet()) {
            JobRegistryDetailBO registry = new JobRegistryDetailBO();
            registry.setJobName(jobName);

            // 判断是否支持分片参数
            // 如果方法有参数，则支持分片；否则不支持分片
            Method method = jobHandlerMap.get(jobName);
            if (method != null && method.getParameterCount() > 0) {
                // 支持分片
                registry.setSharding(1);
            } else {
                // 不支持分片
                registry.setSharding(0);
            }

            jobRegistryList.add(registry);
        }

        log.info("任务处理器注册信息构建完成，共注册 {} 个处理器", jobRegistryList.size());
        return jobRegistryList;
    }

    /**
     * 执行具体的任务
     * <p>
     * 根据任务名称找到对应的处理器，然后执行任务
     *
     * @param request 任务名称
     * @return 执行结果
     */
    @Override
    public JobExecutorResultDTO executeTask(TaskExecuteRequestDTO request) {
        String jobName = request.getJobName();
        log.info("开始执行任务: {}, 参数: {}", jobName, request);

        JobExecutorParamsDTO params = new JobExecutorParamsDTO();
        params.setShardingParam(request.getShardingParam());
        params.setShardingParamIndex(request.getShardingParamIndex());
        params.setPrevTaskResult(request.getPrevTaskResult());

        try {
            // 获取任务处理器信息
            Method method = jobHandlerMap.get(jobName);
            Object instance = jobHandlerInstanceMap.get(jobName);

            if (method != null && instance != null) {
                // 方法级别的任务处理器
                Object result;
                if (method.getParameterCount() > 0) {
                    // 如果方法有参数，传入参数
                    result = method.invoke(instance, params);
                } else {
                    // 如果方法无参数，不传参数
                    result = method.invoke(instance);
                }

                // 构建执行结果
                JobExecutorResultDTO executorResult = new JobExecutorResultDTO();
                executorResult.setResult(String.valueOf(result));
                return executorResult;

            } else if (instance instanceof JobExecutorService) {
                // 类级别的任务处理器
                JobExecutorService service = (JobExecutorService) instance;
                return service.execute(params);

            } else {
                log.error("未找到任务处理器: {}", jobName);
                throw new RuntimeException("未找到任务处理器: " + jobName);
            }

        } catch (Exception e) {
            log.error("执行任务失败: {}", jobName, e);
            // 构建错误结果
            JobExecutorResultDTO errorResult = new JobExecutorResultDTO();
            errorResult.setResult("执行失败: " + e.getMessage());
            return errorResult;
        }
    }
}
